﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Threading;
using System.Net;
using System.Net.Sockets;
using System.IO;

namespace Networking
{
    public class ClientManager
    {
        public string IP { get; set; }
        public int Port { get; set; }
        private UdpClient Client;
        public int ID { get; set; }
        public int ClientsCount { get; set; }
        public bool Connected { get { return Client.Client.Connected; } }
        public delegate void ClientConnectEventHandler(int port);
        public delegate void ReceiveDataEventHandler(Headers header, SubHeaders subheader, string data);
        public delegate void ServerShutdownEventHandler(int port);
        public event ClientConnectEventHandler OnClientConnect;
        public event ReceiveDataEventHandler OnReceiveData;
        public event ServerShutdownEventHandler OnServerShutdown;


        public ClientManager(string ip, int port)
        {
            IP = ip;
            Port = port;
            Client = new UdpClient(new IPEndPoint(IPAddress.Parse(ip), port));
        }

        public void Connect()
        {
            try
            {
                Client.Connect(new IPEndPoint(IPAddress.Parse(IP), Port));
                
     
                Thread thrdReceive = new Thread(new ThreadStart(ReceiveData));
                thrdReceive.Start();
            }
            catch (Exception ex)
            {
                Console.WriteLine("ERROR: " + ex.ToString()); //Debug Error
            }
        }

        public void RequestClientsCount()
        {
            try
            {
                SendData(SubHeaders.TotalClients, "", ID);
            }
            catch (Exception ex)
            {
                Console.WriteLine("ERROR: " + ex.ToString()); //Debug Error
            }
        }

        public void SendData(SubHeaders subheader, string data, int clientid = -1)
        {
            try
            {
                if (clientid != -1)
                {
                    PacketWriter packetwriter = new PacketWriter();
                    packetwriter.Write((ushort)Headers.ClientToClient);
                    packetwriter.Write(clientid);
                    packetwriter.Write((ushort)subheader);
                    packetwriter.Write(data);
                    byte[] databuffer = packetwriter.GetBytes();
                    NetStream.Write(databuffer, 0, databuffer.Length);
                }
                else
                {
                    PacketWriter packetwriter = new PacketWriter();
                    packetwriter.Write((ushort)Headers.ClientToServer);
                    packetwriter.Write((ushort)subheader);
                    packetwriter.Write(data);
                    byte[] databuffer = packetwriter.GetBytes();
                    NetStream.Write(databuffer, 0, databuffer.Length);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("ERROR: " + ex.ToString()); //Debug Error
            }
        }

        public void SendObject(SubHeaders subheader, object obj, int clientid = -1)
        {
            try
            {
                if (clientid != -1)
                {
                    PacketWriter packetwriter = new PacketWriter();
                    packetwriter.Write((ushort)Headers.ClientToClient);
                    packetwriter.Write(clientid);
                    packetwriter.Write((ushort)subheader);
                    packetwriter.WriteObject(obj);
                    byte[] databuffer = packetwriter.GetBytes();
                    NetStream.Write(databuffer, 0, databuffer.Length);
                }
                else
                {
                    PacketWriter packetwriter = new PacketWriter();
                    packetwriter.Write((ushort)Headers.ClientToServer);
                    packetwriter.Write((ushort)subheader);
                    packetwriter.WriteObject(obj);
                    byte[] databuffer = packetwriter.GetBytes();
                    NetStream.Write(databuffer, 0, databuffer.Length);
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("ERROR: " + ex.ToString()); //Debug Error
            }
        }

        private void ReceiveData()
        {
            int buffersize;
            byte[] databuffer;
            int clientid = -1;
            string data;

            while (true)
            {
                try
                {
                    databuffer = new byte[1024];
                    buffersize = NetStream.Read(databuffer, 0, databuffer.Length);
                    PacketReader packetreader = new PacketReader(databuffer);
                    Headers header = (Headers)packetreader.ReadInt16();
                    if (header == Headers.ClientToClient) clientid = packetreader.ReadInt32();
                    SubHeaders subheader = (SubHeaders)packetreader.ReadInt16();
                    data = packetreader.ReadString();

                    switch (subheader)
                    {
                        case SubHeaders.ClientID:

                            ID = int.Parse(data);

                            break;

                        case SubHeaders.TotalClients:

                            ClientsCount = int.Parse(data);

                            break;
                    }

                    if (buffersize != 0)
                    {
                        if (OnReceiveData != null) OnReceiveData(header, subheader, data, clientid);
                    }
                    else
                    {
                        if (OnServerShutdown != null) OnServerShutdown(Port);
                    }
                }
                catch (Exception ex)
                {
                    Console.WriteLine("ERROR: " + ex.ToString()); //Debug Error
                }
            }
        }
    }
}
